package com.fight.strive.sys.modules.rbac.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fight.strive.sys.modules.common.PageR;
import com.fight.strive.sys.modules.exception.StriveException;
import com.fight.strive.sys.modules.mybatis.MyBatisPlusUtils;
import com.fight.strive.sys.modules.rbac.dao.RbacDepartmentMapper;
import com.fight.strive.sys.modules.rbac.dto.RbacDepartmentTreeDto;
import com.fight.strive.sys.modules.rbac.entity.RbacDepartmentEntity;
import com.fight.strive.sys.modules.rbac.service.RbacDepartmentService;
import com.fight.strive.sys.modules.rbac.service.RbacUserDepartmentService;
import com.fight.strive.sys.modules.redis.RedisUtils;
import com.fight.strive.sys.utils.ObjectUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class RbacDepartmentServiceImpl
        extends ServiceImpl<RbacDepartmentMapper, RbacDepartmentEntity>
        implements RbacDepartmentService {

    private final String idKey = "sys:rbac_department:id";

    @Resource
    private RbacUserDepartmentService rbacUserDepartmentService;

    @Override
    public void saveDepartment(RbacDepartmentEntity entity) {
        try {
            if (ObjectUtils.isNull(entity.getParentId())) {
                entity.setParentId(0L);
            }
            this.saveOrUpdate(entity);
            entity = this.getById(entity.getId());
            this.updateCache(entity);
        } catch (DuplicateKeyException e) {
            throw new StriveException("部门编号存在重复");
        }
    }

    @Override
    public RbacDepartmentEntity getDeparmentById(Long id) {
        RbacDepartmentEntity entity = RedisUtils.hashGet(
                idKey, id, RbacDepartmentEntity.class);
        if (ObjectUtils.isNull(entity)) {
            entity = this.getById(id);
            if (ObjectUtils.notNull(entity)) {
                this.updateCache(entity);
            }
        }
        return entity;
    }

    @Override
    public IPage<RbacDepartmentEntity> listByPage(PageR<RbacDepartmentEntity> page) {
        QueryWrapper<RbacDepartmentEntity> queryWrapper = new QueryWrapper<>();
        MyBatisPlusUtils.buildRuleQuery(queryWrapper, page);
        return this.page(page, queryWrapper);
    }

    @Override
    public List<RbacDepartmentEntity> listDepartmentsByParentId(Long parentId) {
        if (ObjectUtils.isNull(parentId)) {
            parentId = 0L;
        }
        QueryWrapper<RbacDepartmentEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("parent_id", parentId);
        return this.list(queryWrapper);
    }

    @Override
    public List<RbacDepartmentTreeDto> getDepartmentTree(Long parentId) {
        List<RbacDepartmentTreeDto> nodes = new ArrayList<>();
        List<RbacDepartmentEntity> departments = this.listDepartmentsByParentId(parentId);
        for (RbacDepartmentEntity entity : departments) {
            RbacDepartmentTreeDto node = new RbacDepartmentTreeDto(entity.getId(), entity.getName(), entity);
            node.setChildren(this.getDepartmentTree(entity.getId()));
            nodes.add(node);
        }
        return nodes;
    }

    @Override
    @Transactional
    public void removeDepartment(Long id) {
        RbacDepartmentEntity entity = this.getById(id);
        this.removeCache(entity);
        this.removeById(entity);
        // 删除部门用户关联信息，不删除用户信息
        rbacUserDepartmentService.removeByDepartmentId(id);
    }

    @Override
    public void updateCache(RbacDepartmentEntity entity) {
        if (ObjectUtils.notNull(entity)
                && ObjectUtils.notNull(entity.getId())) {
            RedisUtils.hashPut(idKey, entity.getId(), entity);
        }
    }

    @Override
    public void removeCache(RbacDepartmentEntity entity) {
        if (ObjectUtils.notNull(entity)
                && ObjectUtils.notNull(entity.getId())) {
            RedisUtils.hashDelete(idKey, entity.getId());
        }
    }
}
